package com.peak.distribution.service.agent;

import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.peak.distribution.config.security.SessionUser;
import com.peak.distribution.entity.admin.DisRole;
import com.peak.distribution.entity.admin.DisSmsLog;
import com.peak.distribution.entity.admin.DisSmsTemplate;
import com.peak.distribution.entity.admin.DisUser;
import com.peak.distribution.entity.agent.DisAgent;
import com.peak.distribution.entity.agent.DisAgentAccount;
import com.peak.distribution.entity.agent.DisAgentAward;
import com.peak.distribution.entity.agent.DisAgentSales;
import com.peak.distribution.entity.agent.DisAgentTeam;
import com.peak.distribution.enums.AccountType;
import com.peak.distribution.enums.AgentLevel;
import com.peak.distribution.enums.SmsType;
import com.peak.distribution.exception.DistributionError;
import com.peak.distribution.exception.DistributionException;
import com.peak.distribution.jms.JmsProducerHandler;
import com.peak.distribution.manager.admin.DisSmsLogManager;
import com.peak.distribution.manager.admin.DisSmsTemplateManager;
import com.peak.distribution.manager.admin.DisUserManager;
import com.peak.distribution.manager.agent.DisAgentAccountManager;
import com.peak.distribution.manager.agent.DisAgentAwardManager;
import com.peak.distribution.manager.agent.DisAgentManager;
import com.peak.distribution.manager.agent.DisAgentSalesManager;
import com.peak.distribution.manager.agent.DisAgentTeamManager;
import com.peak.distribution.tools.SpringSecuritys;
import com.peak.spring.boot.builder.repository.FilterParamBuilder;
import com.peak.spring.boot.core.repository.JpaSorts;
import com.peak.spring.boot.tools.Converts;
import com.peak.spring.boot.tools.Dates;
import com.peak.spring.boot.tools.Emptys;

@Transactional
@Service
public class DisAgentServiceImpl implements DisAgentService {
	
	@Value("${team.default.suffix}")
	private String teamDefaultSuffix;

	@Autowired
	private DisAgentManager agentManager;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private DisUserManager userManager;
	
	@Autowired
	private DisSmsLogManager smsLogManager;
	
	@Autowired
	private DisSmsTemplateManager smsTemplateManager;
	
	@Autowired
	private DisAgentTeamManager agentTeamManager;
	
	@Autowired
	private DisAgentAccountManager agentAccountManager;
	
	@Autowired
	private DisAgentAwardManager agentAwardManager;
	
	@Autowired
	private DisAgentSalesManager agentSalesManager;
	
	@Autowired
	private JmsProducerHandler jmsProducerHandler;

	@Transactional(readOnly = true)
	@Override
	public DisAgent getCurrentAgent() {
		SessionUser loginUser = SpringSecuritys.getLoginUser();
		if (loginUser == null) {
			return null;
		}
		return agentManager.getByUserId(loginUser.getId());
	}

	@Override
	public Integer getCurrentAgentId() {
		SessionUser loginUser = SpringSecuritys.getLoginUser();
		if (loginUser == null) {
			return null;
		}
		return loginUser.getAgentId();
	}

	@Override
	public void changePassword(Map<String, Object> params) {
		// 取出当前用户
		DisAgent agent = getCurrentAgent();
		DisUser user = agent.getUser();
		// 把几个相关的密码都取出来
		String oldPwd = Converts.toString(params.get("oldPwd"));
		String newPwd = Converts.toString(params.get("newPwd"));
		String newPwd2 = Converts.toString(params.get("newPwd2"));
		String dbPwd = user.getPassword();
		// 两次新密码必须一样
		if (!StringUtils.equals(newPwd, newPwd2)) {
			throw new DistributionException(DistributionError.USER_PWD2_NOT_EQUAL_PWD);
		}
		// 原密码需要和数据库密码一样
		if (!passwordEncoder.matches(oldPwd, dbPwd)) {
			throw new DistributionException(DistributionError.USER_PWD_INCORRECT);
		}
		// 更新密码
		user.setPassword(passwordEncoder.encode(newPwd));
		userManager.save(user);
	}

	@Override
	public void resetPassword(Map<String, Object> params) {
		// 取出必要的参数并转换为String
		String mobileNo = Converts.toString(params.get("mobileNo"));
		String captchaCode = Converts.toString(params.get("captchaCode"));
		String newPwd = Converts.toString(params.get("newPwd"));
		String newPwd2 = Converts.toString(params.get("newPwd2"));
		
		checkMobileCode(mobileNo, captchaCode, SmsType.FORGOT_PASSWORD);
		// 两次密码需要一致
		if (!StringUtils.equals(newPwd, newPwd2)) {
			throw new DistributionException(DistributionError.USER_PWD2_NOT_EQUAL_PWD);
		}
		// 查找代理商是否存在
		DisAgent agent = agentManager.getByMobileNo(mobileNo);
		if (agent == null) {
			throw new DistributionException(DistributionError.AGENT_NOT_FOUND);
		}
		
		// 覆盖老的用户密码
		DisUser user = agent.getUser();
		user.setPassword(passwordEncoder.encode(newPwd));
		userManager.save(user);
	}

	@Override
	public void checkMobileCode(String mobileNo, String captchaCode, SmsType smsType) {
		// 从短信的日志中找找短信
		DisSmsLog smsLog = smsLogManager.findFirstOne(FilterParamBuilder.create()
				.eq("mobileNos", mobileNo)
				.eq("type", smsType).build(), JpaSorts.desc("sendTime"));
		if (smsLog == null) {
			throw new DistributionException(DistributionError.SMS_CODE_NOT_FOUND);
		}
		// 看看是否超时，默认30分钟
		Date now = Dates.addMinute(Dates.now(), -30);
		if (smsLog.getSendTime().before(now)) {
			throw new DistributionException(DistributionError.SMS_CODE_EXPIRE);
		}
		
		// 比较短信内容是否一致
		DisSmsTemplate template = smsTemplateManager.getTemplateByType(smsType);
		if (!StringUtils.equals(MessageFormat.format(template.getTemplate(), captchaCode), smsLog.getContent())) {
			throw new DistributionException(DistributionError.SMS_CODE__NOT_EQUAL);
		}
	}

	@Override
	public void addSubAgent(Map<String, Object> data, DisAgent parentAgent, boolean needModifyPassword) {
		DisAgent agent = Converts.fromMap(data, DisAgent.class);
		// 代理不需要填入的属性
		agent.setLevel(AgentLevel.NORMAL);
		agent.setJoinTime(Dates.now());
		agent.setParent(parentAgent);
		agent.setSubAgentCount(0); // 默认没有下级代理
		agent.setSex(Boolean.FALSE);// 默认女性
		agent.setAuditStatus(Boolean.FALSE); // 默认需要审核
		// 代理的登录用户表
		DisUser user = new DisUser();
		user.setUsername(Converts.toString(data.get("mobileNo")));
		user.setPassword(passwordEncoder.encode(Converts.toString(data.get("password"))));
		user.setNeedModifyPassword(needModifyPassword);
		user.setIsTest(Boolean.FALSE);
		// 沿用父代理的角色
		DisRole role = parentAgent.getUser().getRole();
		user.setRole(role);
		// 设置登录用户
		agent.setUser(user);
		
		// 自己组件的团队
		DisAgentTeam selfTeam = new DisAgentTeam();
		selfTeam.setLeader(agent);
		selfTeam.setName(agent.getName() + teamDefaultSuffix);
		selfTeam.getMembers().add(agent);

		// 先保存代理商信息，目的是得到ID
		userManager.save(user);
		agentManager.save(agent);
		agentTeamManager.save(selfTeam);
		
		// 代理的账户
		List<DisAgentAccount> accounts = Lists.newArrayList();
		// 银行卡账户
		String bank = Converts.toString(data.get("bank"));
		String bankCard = Converts.toString(data.get("bankCard"));
		if (Emptys.isNotMemberEmpty(bank, bankCard)) {
			DisAgentAccount bankAccount = createAccount(AccountType.BANK, bankCard);
			bankAccount.setBank(bank);
			bankAccount.setAgent(agent);
			accounts.add(bankAccount);
		}
		// 支付宝账户
		String zhifubao = Converts.toString(data.get("zhifubao"));
		if (Emptys.isNotEmpty(zhifubao)) {
			DisAgentAccount zhifubaoAccount = createAccount(AccountType.ZHIFUBAO, zhifubao);
			zhifubaoAccount.setAgent(agent);
			accounts.add(zhifubaoAccount);
		}
		// 微信账户
		String wxPay = Converts.toString(data.get("wxPay"));
		if (Emptys.isNotEmpty(wxPay)) {
			DisAgentAccount wxAccount = createAccount(AccountType.WEIXIN, wxPay);
			wxAccount.setAgent(agent);
			accounts.add(wxAccount);
			// 微信就一个帐号
			agent.setWechat(wxPay);
		}
		// 总账户
		DisAgentAccount totalAccount = createAccount(AccountType.TOTAL, null);
		totalAccount.setAgent(agent);
		accounts.add(totalAccount);
		
		// 所有父级的团队都要加入
		List<DisAgentTeam> teams = agentTeamManager.getAllTeam(parentAgent);
		teams.stream().forEach(p -> p.getMembers().add(agent));
		
		// 初始化奖金都为0
		DisAgentAward award = new DisAgentAward();
		award.setAgent(agent);
		award.setDayAmount(0);
		award.setMonthAmount(0);
		award.setQuarterAmount(0);
		award.setTotalAmount(0);
		award.setWeekAmount(0);
		award.setSign(passwordEncoder.encode(award.getSignSource()));
		
		// 初始化奖金都为0
		DisAgentAward teamAward = new DisAgentAward();
		teamAward.setTeam(selfTeam);
		teamAward.setDayAmount(0);
		teamAward.setMonthAmount(0);
		teamAward.setQuarterAmount(0);
		teamAward.setTotalAmount(0);
		teamAward.setWeekAmount(0);
		teamAward.setSign(passwordEncoder.encode(teamAward.getSignSource()));
		
		// 初始化销量表
		DisAgentSales sales = new DisAgentSales();
		sales.setAgent(agent);
		sales.setDaySales(0);
		sales.setMonthSales(0);
		sales.setQuarterSales(0);
		sales.setTotalSales(0);
		sales.setWeekSales(0);
		sales.setTotalGoodsCount(0);
		sales.setSign(passwordEncoder.encode(sales.getSignSource()));
		
		DisAgentSales teamSales = new DisAgentSales();
		teamSales.setTeam(selfTeam);
		teamSales.setDaySales(0);
		teamSales.setMonthSales(0);
		teamSales.setQuarterSales(0);
		teamSales.setTotalSales(0);
		teamSales.setWeekSales(0);
		teamSales.setTotalGoodsCount(0);
		teamSales.setSign(passwordEncoder.encode(teamSales.getSignSource()));
		
		// 保存数据库内容
		agentAccountManager.save(accounts);
		agentTeamManager.save(teams);
		agentAwardManager.save(award);
		agentAwardManager.save(teamAward);
		agentSalesManager.save(sales);
		agentSalesManager.save(teamSales);
		// 父级代理增加代理数量
		jmsProducerHandler.addSubAgentCount(parentAgent.getId());
	}

	private DisAgentAccount createAccount(AccountType type, String accountNo) {
		DisAgentAccount account = new DisAgentAccount();
		account.setType(type);
		account.setAccountNo(accountNo);
		account.setTotalIncome(0);
		account.setTotalPayout(0);
		// 加一个签名保证账户的数据变化是可以判断是否正确
		account.setSign(passwordEncoder.encode(account.getSignSource()));
		return account;
	}

	@Override
	public void updateAgentInfo(Map<String, Object> data, DisAgent agent) {
		agent = Converts.fromMap(data, agent);
		Map<AccountType, DisAgentAccount> accounts = agentAccountManager
				.findList(FilterParamBuilder.create().eq("agent.id", agent.getId()).build())
				.stream().collect(Collectors.toMap(DisAgentAccount::getType, p -> p));
		
		// 银行卡账户
		String bank = Converts.toString(data.get("bank"));
		String bankCard = Converts.toString(data.get("bankCard"));
		if (Emptys.isNotMemberEmpty(bank, bankCard)) {
			DisAgentAccount bankAccount = accounts.get(AccountType.BANK);
			if (bankAccount == null) {
				bankAccount = createAccount(AccountType.BANK, bankCard);
				bankAccount.setAgent(agent);
				accounts.put(AccountType.BANK, bankAccount);
			}
			bankAccount.setBank(bank);
			bankAccount.setAccountNo(bankCard);
		}
		// 支付宝账户
		String zhifubao = Converts.toString(data.get("zhifubao"));
		if (Emptys.isNotEmpty(zhifubao)) {
			DisAgentAccount zhifubaoAccount = accounts.get(AccountType.ZHIFUBAO);
			if (zhifubaoAccount == null) {
				zhifubaoAccount = createAccount(AccountType.ZHIFUBAO, zhifubao);
				zhifubaoAccount.setAgent(agent);
				accounts.put(AccountType.ZHIFUBAO, zhifubaoAccount);
			}
			zhifubaoAccount.setAccountNo(zhifubao);
		}
		// 微信账户
		String wxPay = Converts.toString(data.get("wxPay"));
		if (Emptys.isNotEmpty(wxPay)) {
			DisAgentAccount wxAccount = accounts.get(AccountType.WEIXIN);
			if (wxAccount == null) {
				wxAccount = createAccount(AccountType.WEIXIN, zhifubao);
				wxAccount.setAgent(agent);
				accounts.put(AccountType.WEIXIN, wxAccount);
			}
			wxAccount.setAccountNo(wxPay);
			// 微信就一个帐号
			agent.setWechat(wxPay);
		}
		
		// 总账户
		DisAgentAccount totalAccount = accounts.get(AccountType.TOTAL);
		if (totalAccount == null) {
			totalAccount = createAccount(AccountType.TOTAL, null);
			totalAccount.setAgent(agent);
			accounts.put(AccountType.TOTAL, totalAccount);
		}
		
		agentManager.save(agent);
		agentAccountManager.save(accounts.values());
	}

}
